package com.hzw.saas.common.config.aspect;

import com.hzw.saas.common.config.annotation.RedisProcessLock;
import com.hzw.saas.common.util.SpringELUtils;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;

/**
 * Redis分布式锁切面服务
 */
@Aspect
@Component
@RequiredArgsConstructor
@Order(2)
public class RedisLockAspect {

    public static final String REDISSON_LOCK_PREFIX = "REDISSON_LOCK:";

    private final RedissonClient redissonClient;

    @Around("@annotation(processLock)")
    public Object aroundProcess(ProceedingJoinPoint joinPoint, RedisProcessLock processLock) throws Throwable {
        String redisKey = getRedisKey(joinPoint, processLock.lockName(), processLock.key());
        RLock rLock = redissonClient.getLock(redisKey);

        if (processLock.expire() == -1) {
            // 续命锁
            rLock.lock();
        } else {
            // 轮询锁
            rLock.lock(processLock.expire(), processLock.timeUnit());
        }

        Object result = null;
        try {
            //执行方法
            result = joinPoint.proceed();

        } finally {
            rLock.unlock();
        }
        return result;
    }

    /**
     * 将spel表达式转换为字符串
     *
     * @param joinPoint 切点
     * @return redisKey
     */
    private String getRedisKey(JoinPoint joinPoint, String lockName, String spel) {
        String spelValue = "";
        if (StringUtil.isNotBlank(spel)) {
            spelValue = SpringELUtils.getSpelValue(joinPoint, spel, String.class);
        }
        return REDISSON_LOCK_PREFIX + lockName + StrUtil.COLON + spelValue;
    }

}
